import moment from "moment"
import julian from "julian"
import * as satellite from "satellite.js"

const Cesium = DE.__namespace.Cesium
/*
根据卫星显示的起始时间，终止时间，tle轨道两行数得出czml文件，时间为js的Date对象，tles为对象数组，对象格式为
{
name：xx，
tle1：xx，
tle2：xx
}
*/

const DEFAULT_SATELLITE_MODE_URL = "model/weixing.gltf"
export default function tles2czml(startTime, endTime, tles) {
  console.log(endTime)
  console.log(startTime)
  // 计算起始时间和终止时间相隔的分钟数
  const minsInDuration = (endTime.getTime() - startTime.getTime()) / 6000 // mins
  // 设置为开始时间
  const initialTime = moment(startTime.toISOString()).toISOString()
  // 设置为结束时间
  endTime = moment(endTime.toISOString()).toISOString()
  // 初始化czml数据，创建场景信息
  const tempCZML = []
  tempCZML.push({
    id: "document",
    name: "CZML Point - Time Dynamic",
    version: "1.0",
    clock: {
      interval: `${initialTime}/${endTime}`,
      currentTime: initialTime,
      multiplier: 60,
      range: "LOOP_STOP",
      step: "SYSTEM_CLOCK_MULTIPLIER"
    }
  })

  // 处理每一个sat
  for (let no = 0; no < tles.length; no++) {
    if (!tles[no].name) {
      console.log("请输入第" + no + 1 + "个卫星的名称")
      return
    }
    if (!tles[no].tle1) {
      console.log("请输入第" + no + 1 + "个卫星的第一个两行数")
      return
    }
    if (!tles[no].tle2) {
      console.log("请输入第" + no + 1 + "个卫星的第二个两行数")
      return
    }
    const sat_name = tles[no].name
    // 保存位置信息
    const res = []
    const satrec = satellite.twoline2satrec(tles[no].tle1, tles[no].tle2)
    // satrec.no：以弧度/分钟为单位的平均运动，一天有1440分钟，一弧度是0.159155圈
    // to go from RAD/DAY -> REV/DAY: rad * 1440 * 0.159155
    // to go from REV/PER DAY to MINS/REV -> 1440/RevPerDay
    const totalIntervalsInDay = satrec.no * 1440 * 0.159155 // 1440 = min && 0.159155 = 1turn
    // 获得运行一圈的分钟数
    const minsPerInterval = 1440 / totalIntervalsInDay // mins for 1 revolution around earth
    // intervalTime 取起始时间 格式为2008-09-20T12:25:40.104Z
    let intervalTime = moment(startTime.toISOString()).toISOString()

    const leadIntervalArray = []
    const trailIntervalArray = []
    console.log("Setting intervals...")
    // 注意：这里之所以要倒过来求leadInterval和trailInterval是因为如果正着求，很有可能在终止时刻卫星并没有运行完一圈，导致轨道只显示一半
    for (let i = minsInDuration; i >= 0; i -= minsPerInterval) {
      if (i <= minsPerInterval) {
        // intial interval
        const currentOrbitalInterval = {
          interval: `${startTime.toISOString()}/${intervalTime}`,
          epoch: `${startTime.toISOString()}`,
          number: [0, minsPerInterval * 60, minsPerInterval * 60, 0]
        }
        const currTrail = {
          interval: `${startTime.toISOString()}/${intervalTime}`,
          epoch: `${startTime.toISOString()}`,
          number: [0, 0, minsPerInterval * 60, minsPerInterval * 60]
        }
        leadIntervalArray.push(currentOrbitalInterval)
        trailIntervalArray.push(currTrail)
      } else {
        // not initial so make intervals
        const previousIntervalTime = moment(intervalTime).add(-minsPerInterval, "m").toISOString()
        const currentOrbitalInterval = {
          interval: `${previousIntervalTime}/${intervalTime}`,
          epoch: `${previousIntervalTime}`,
          number: [0, minsPerInterval * 60, minsPerInterval * 60, 0]
        }
        const currTrail = {
          interval: `${previousIntervalTime}/${intervalTime}`,
          epoch: `${previousIntervalTime}`,
          number: [0, 0, minsPerInterval * 60, minsPerInterval * 60]
        }
        intervalTime = moment(intervalTime).add(-minsPerInterval, "m").toISOString()
        leadIntervalArray.push(currentOrbitalInterval)
        trailIntervalArray.push(currTrail)
      }
    }
    // Seconds between current time and epoch time
    const sec = (startTime - julian.toDate(satrec.jdsatepoch)) / 1000
    console.log(startTime, julian.toDate(satrec.jdsatepoch), sec)
    for (let i = sec; i <= sec + minsInDuration * 60; i++) {
      // 每60秒计算一个位置信息，最后采用拉格朗日插值法处理数据
      // 根据当前时间距tle两行数历元时刻的分钟数，计算当前卫星位置和速度
      const positionAndVelocity = satellite.sgp4(satrec, i * 0.0166667) // 0.0166667min = 1sec
      // 地惯坐标系
      const positionEci = positionAndVelocity.position
      positionEci.x = positionEci.x * 1000
      positionEci.y = positionEci.y * 1000
      positionEci.z = positionEci.z * 1000
      // let velocityEci = positionAndVelocity.velocity;
      // velocityEci.x = velocityEci.x * 1000;
      // velocityEci.y = velocityEci.y * 1000;
      // velocityEci.z = velocityEci.z * 1000;
      res.push(i - sec, positionEci.x, positionEci.y, positionEci.z)
    }
    const initialCZMLProps = {
      id: `${sat_name}`,
      name: `${sat_name}`,
      availability: `${initialTime}/${endTime}`,
      label: {
        fillColor: {
          rgba: [255, 0, 255, 255]
        },
        font: "11pt Lucida Console",
        horizontalOrigin: "LEFT",
        outlineColor: {
          rgba: [0, 0, 0, 255]
        },
        outlineWidth: 2,
        pixelOffset: {
          cartesian2: [12, 0]
        },
        show: true,
        style: "FILL_AND_OUTLINE",
        text: `${sat_name}`,
        verticalOrigin: "CENTER"
      },
      path: {
        show: [
          {
            interval: `${initialTime}/${endTime}`,
            boolean: true
          }
        ],
        width: 3,
        material: {
          solidColor: {
            color: {
              rgba: [
                // 随机生成轨道颜色
                Math.floor(255 * Math.random(0, 1)),
                Math.floor(255 * Math.random(0, 1)),
                Math.floor(255 * Math.random(0, 1)),
                255
              ]
            }
          }
        },
        resolution: 120,
        // The time ahead of the animation time, in seconds, to show the path.
        leadTime: leadIntervalArray,
        // The time behind the animation time, in seconds, to show the
        trailTime: trailIntervalArray
      },
      model: {
        show: true,
        gltf: DEFAULT_SATELLITE_MODE_URL,
        minimumPixelSize: 55
      },
      position: {
        // 采用拉格朗日插值法
        interpolationAlgorithm: "LAGRANGE",
        // 1为线性插值，2为平方插值
        interpolationDegree: 2,
        // 参考坐标系，地惯坐标系
        referenceFrame: "INERTIAL",
        epoch: `${initialTime}`,
        cartesian: res
      },
      orientation: {
        // 设置模型转向方法，根据position进行四元数方向转换
        velocityReference: "#position"
      }
    }
    tempCZML.push(initialCZMLProps)
  }
  return tempCZML
}


let arrStates = []
let start, stop, viewer
export function simulation(v, startTime, endTime) {
  viewer = v
  // start = new Cesium.JulianDate.fromDate(new Date()); // 获取当前时间 这不是国内的时间
  start = new Cesium.JulianDate.fromDate(startTime) // 获取当前时间 这不是国内的时间
  stop = new Cesium.JulianDate.fromDate(endTime) // 获取当前时间 这不是国内的时间
  console.log(start)
  const sec = stop.secondsOfDay - start.secondsOfDay
  // start = Cesium.JulianDate.addHours(start, 8, new Cesium.JulianDate()); // 添加八小时，得到我们东八区的北京时间
  // stop = Cesium.JulianDate.addHours(stop, 8, new Cesium.JulianDate()); // 设置一个结束时间，意思是360秒之后时间结束

  viewer.clock.startTime = start.clone() // 给cesium时间轴设置开始的时间，也就是上边的东八区时间
  viewer.clock.stopTime = stop.clone() // 设置cesium时间轴设置结束的时间
  viewer.clock.currentTime = start.clone() // 设置cesium时间轴设置当前的时间
  viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP // 时间结束了，再继续重复来一遍
  // 时间变化来控制速度 // 时间速率，数字越大时间过的越快
  viewer.clock.multiplier = 2
  // 给时间线设置边界
  viewer.timeline.zoomTo(start, stop)

  arrStates = []
  getRandState(arrStates, 1, sec)
  startFunc()
}
function mySatePosition() {
  this.lon = 0
  this.lat = 0
  this.hei = 700000 // 卫星高度
  this.phei = 700000 / 2 // 轨道高度
  this.time = 0
}
function computeCirclularFlight(source, panduan) {
  const property = new Cesium.SampledPositionProperty()
  if (panduan === 1) {
    // 卫星位置
    for (let i = 0; i < source.length; i++) {
      const time = Cesium.JulianDate.addSeconds(start, source[i].time, new Cesium.JulianDate())
      const position = Cesium.Cartesian3.fromDegrees(source[i].lon, source[i].lat, source[i].hei)
      // 添加位置，和时间对应
      property.addSample(time, position)
    }
  } else if (panduan === 2) {
    // 轨道位置
    for (let i = 0; i < source.length; i++) {
      const time = Cesium.JulianDate.addSeconds(start, source[i].time, new Cesium.JulianDate())
      const position = Cesium.Cartesian3.fromDegrees(source[i].lon, source[i].lat, source[i].phei)
      // 添加位置，和时间对应
      property.addSample(time, position)
    }
  }
  return property
}

function getRandState(brr, count, sec) {
  for (let m = 0; m < count; m++) {
    const arr = []
    const t1 = Math.floor(Math.random() * sec)
    const t2 = Math.floor(Math.random() * sec)
    for (let i = t1; i <= sec + t1; i += 30) {
      const aaa = new mySatePosition()
      aaa.lon = t2
      aaa.lat = i
      aaa.time = i - t1
      arr.push(aaa)
    }
    brr.push(arr)
  }
  console.log(brr)
}

function getStatePath(aaa) {
  console.log(aaa)
  console.log(viewer)

  const entity_ty1p = computeCirclularFlight(aaa, 2)
  const entity_ty1 = viewer.entities.add({
    availability: new Cesium.TimeIntervalCollection([
      new Cesium.TimeInterval({
        start: start,
        stop: stop
      })
    ]),
    position: entity_ty1p, // 轨道高度
    orientation: new Cesium.VelocityOrientationProperty(entity_ty1p),
    cylinder: {
      HeightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      length: 700000,
      topRadius: 0,
      bottomRadius: 900000 / 2,
      // material: Cesium.Color.RED.withAlpha(.4),
      // outline: !0,
      numberOfVerticalLines: 0,
      // outlineColor: Cesium.Color.RED.withAlpha(.8),
      material: Cesium.Color.fromBytes(35, 170, 242, 80)
    }
  })

  entity_ty1.position.setInterpolationOptions({
    interpolationDegree: 5,
    interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
  })

  const entity1p = computeCirclularFlight(aaa, 1)
  // 创建实体
  const entity1 = viewer.entities.add({
    // 将实体availability设置为与模拟时间相同的时间间隔。
    availability: new Cesium.TimeIntervalCollection([
      new Cesium.TimeInterval({
        start: start,
        stop: stop
      })
    ]),
    position: entity1p, // 计算实体位置属性
    // 基于位置移动自动计算方向.
    orientation: new Cesium.VelocityOrientationProperty(entity1p),
    // 加载飞机模型
    model: {
      uri: DEFAULT_SATELLITE_MODE_URL,
      scale: 30000
    },
    // 路径
    path: {
      resolution: 1,
      material: new Cesium.PolylineGlowMaterialProperty({
        glowPower: 0.1,
        color: Cesium.Color.PINK
      }),
      width: 5
    }
  })

  // 差值器
  entity1.position.setInterpolationOptions({
    interpolationDegree: 5,
    interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
  })
}

function startFunc() {
  for (let i = 0; i < arrStates.length; i++) {
    getStatePath(arrStates[i])
  }
}
